//---------------------------------------------------------------------
//  This file is part of the Background Motion solution.
// 
//  Copyright (C) Mindscape (TM).  All rights reserved.
//  http://www.mindscape.co.nz
// 
//  THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

using Microsoft.Practices.EnterpriseLibrary.Validation;
using Mindscape.BackgroundMotion.Core.Validators;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace Mindscape.BackgroundMotion.Model
{
  /// <summary>
  /// Represents a Tag in the system
  /// </summary>
  /// <remarks>
  /// Tags are associated with Contributions as members add metadata about the contributions relevance to them
  /// </remarks>
  [Table(Name = "Tag")]
  public sealed class Tag : ModelObject
  {
    public const string BannedWordsResourcePath = "Mindscape.BackgroundMotion.Model.Properties.BannedWords.txt";

    private static readonly Dictionary<string, object> _bannedWords 
      = new Dictionary<string, object>();

    /// <summary>
    /// Initializes the tag with the list of banned words
    /// </summary>
    static Tag()
    {
      using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(BannedWordsResourcePath))
      {
        using (StreamReader reader = new StreamReader(stream))
        {
          while (!reader.EndOfStream)
          {
            _bannedWords[reader.ReadLine().Trim()] = null;
          }
        }
      }
             
    }

    private int _id;

    private string _value;
    private string _loweredValue;
    private int _usages;

    private EntitySet<ContributionTag> _contributionTags;

    /// <summary>
    /// Indicates if a potential tag matches one of the banned words
    /// </summary>
    /// <param name="tag">The tag which is being analyzed</param>
    /// <returns>true if the tag is found in the banned list, else false</returns>
    public static bool IsBannedTag(string tag)
    {
      return _bannedWords.ContainsKey(tag.ToLower());
    }

    public Tag()
    {
      _contributionTags = CreateEntitySet<ContributionTag>(
        (ContributionTag c) => c.Tag = null,
        (ContributionTag c) => c.Tag = this);

      Usages = 1;
    }

    /// <summary>
    /// Validates this instance for a correct state
    /// </summary>
    /// <remarks>
    /// This is called by the Enterprise Library Validation framework
    /// </remarks>
    /// <param name="results">A set of ValidationResults indicating validation issues with the current instance</param>
    protected override void Validate(ValidationResults results)
    {
      results.AddAllResults(Validation.ValidateFromAttributes(this));
    }

    #region Mapped Properties

    [Column(Storage = "_id", IsPrimaryKey = true, IsDbGenerated = true)]
    public override int Id
    {
      get { return _id; }
      set
      {
        if (_id != value)
        {
          OnPropertyChanging("Id");
          _id = value;
          OnPropertyChanged("Id");
        }
      }
    }

    [RequireValidator("Value", 50)]
    [Column(Storage = "_value")]
    public string Value
    {
      get { return _value; }
      set
      {
        if ((_value != value))
        {
          OnPropertyChanging("Value");
          _value = value;
          OnPropertyChanged("Value");

          LoweredValue = (Value != null)
            ? Value.ToLower()
            : Value;
        }
      }
    }

    [RequireValidator("LoweredValue", 50)]
    [Column(Storage = "_loweredValue")]
    public string LoweredValue
    {
      get { return _loweredValue; }
      set
      {
        if ((_loweredValue != value))
        {
          OnPropertyChanging("LoweredValue");
          _loweredValue = value;
          OnPropertyChanged("LoweredValue");
        }
      }
    }

    [Column(Storage = "_usages")]
    public int Usages
    {
      get { return _usages; }
      set
      {
        if ((_usages != value))
        {
          OnPropertyChanging("Usages");
          _usages = value;
          OnPropertyChanged("Usages");
        }
      }
    }

    [Association(Storage = "_contributionTags", OtherKey = "TagId")]
    public EntitySet<ContributionTag> ContributionTags
    {
      get { return _contributionTags; }
      set { _contributionTags.Assign(value); }
    }

    #endregion

    /// <summary>
    /// Returns the tag in a string quoted form for portability
    /// </summary>
    public string QuotedValue
    {
      get { return (Value.IndexOf(' ') >= 0) ? String.Concat("\"", Value, "\"") : Value; }
    }
  }
}